package com.zengfa.task.server.application.impl;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.zengfa.task.api.enums.JobStatus;
import com.zengfa.task.api.enums.JobType;
import com.zengfa.task.api.enums.RunType;
import com.zengfa.task.api.model.JobDTO;
import com.zengfa.task.api.model.JobNodeDTO;
import com.zengfa.task.api.service.ServerApiService;
import com.zengfa.task.api.utils.UuidUtil;
import com.zengfa.task.server.application.JobAppService;
import com.zengfa.task.server.dao.JobDao;
import com.zengfa.task.server.dao.JobNodeDao;
import com.zengfa.task.server.domain.entity.Job;
import com.zengfa.task.server.domain.entity.JobNode;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ServerApiServiceImpl implements ServerApiService {

	@Autowired
	private JobDao jobDao;
	@Autowired
	private JobNodeDao jobNodeDao;
	@Autowired
	private JobAppService jobAppService;
	
	@Override
	@Transactional
	public JobDTO createTask(JobDTO jobDTO) {
		log.info("创建任务:" + JSONObject.toJSONString(jobDTO));
		Job job = jobDao.findJob(jobDTO.getJobGroup(), jobDTO.getBizId());
		if (job != null) {
			BeanUtils.copyProperties(job, jobDTO);
			return jobDTO;
		}
		job = new Job();
		BeanUtils.copyProperties(jobDTO, job);
		job.setJobId(UuidUtil.getUUID32());
		job.setJobType(jobDTO.getJobType().getValue());
		job.setStatus(JobStatus.WAIT);
		job.setInsertTime(LocalDateTime.now());
		jobDao.save(job);
		List<JobNodeDTO> nodeList = jobDTO.getNodeList();
		if (!CollectionUtils.isEmpty(nodeList)) {
			int i = 0;
			for(JobNodeDTO nodeDto : nodeList) {
				JobNode jobNode = new JobNode();
				BeanUtils.copyProperties(nodeDto, jobNode);
				jobNode.setId(UuidUtil.getUUID32());
				jobNode.setJobId(job.getJobId());
				jobNode.setNodeOrder(++i);
				jobNode.setRunType(nodeDto.getRunType().getValue());
				jobNode.setStatus(JobStatus.WAIT);
				jobNode.setInsertTime(LocalDateTime.now());
				jobNodeDao.save(jobNode);
				nodeDto.setId(jobNode.getId());
				nodeDto.setStatus(jobNode.getStatus());
			}
		}
		jobDTO.setJobId(job.getJobId());
		jobDTO.setStatus(job.getStatus());
		return jobDTO;
	}

	@Override
	@Transactional
	public void resetJob(String jobId) {
		Job job = jobDao.getById(jobId);
		if(job == null) {
			return;
		}
		job.setStatus(JobStatus.WAIT);
		job.setLastSyncTime(LocalDateTime.now());
		job.setUpdateTime(LocalDateTime.now());
		job.setStartTime(null);
		job.setEndTime(null);
		job.setExecIp(null);
		jobDao.updateById(job);
		Integer jobType = job.getJobType();
		if(jobType != null && jobType == JobType.FLOW.getValue()) {
			//清空流程任务状态
			List<JobNode> nodeList = jobNodeDao.listByJobId(jobId);
			if (!CollectionUtils.isEmpty(nodeList)) {
				for(JobNode jobNode : nodeList) {
					jobNode.setStatus(JobStatus.WAIT);
					jobNode.setMessage(null);
					jobNode.setUpdateTime(LocalDateTime.now());
					jobNode.setStartTime(null);
					jobNode.setEndTime(null);
					jobNode.setExecIp(null);
					jobNodeDao.updateById(jobNode);
				}
			}
		}
	}
	
	@Override
	public JobNodeDTO getNextRunNode(String jobId) {
		Job job = jobDao.getById(jobId);
		if(job == null) {
			return null;
		}
		List<JobNode> list = jobNodeDao.listByJobId(jobId);
		for(JobNode r : list) {
			JobStatus status = r.getStatus();
			if(JobStatus.ERROR == status || 
					JobStatus.STOP == status) {
				return null;
			}
			if(JobStatus.WAIT != status) {
				continue;
			}
			JobNodeDTO jobNodeDTO = new JobNodeDTO();
			jobNodeDTO.setJobId(job.getJobId());
			jobNodeDTO.setNodeName(r.getNodeName());
			jobNodeDTO.setNodeCode(r.getNodeCode());
			jobNodeDTO.setRunType(RunType.valueOf(r.getRunType()));
			jobNodeDTO.setStatus(status);
			jobNodeDTO.setId(r.getId());
			JobDTO jobDTO = new JobDTO();
			BeanUtils.copyProperties(job, jobDTO);
			jobDTO.setJobType(JobType.valueOf(job.getJobType()));
			jobNodeDTO.setJobDTO(jobDTO);
			return jobNodeDTO;
		}
		return null;
	}
	
	@Override
	public JobNodeDTO getCurrentRunNode(String jobId) {
		Job job = jobDao.getById(jobId);
		if(job == null || job.getJobType() == JobType.SINGLE.getValue()) {
			return null;
		}
		List<JobNode> list = jobNodeDao.listByJobId(jobId);
		for(JobNode r : list) {
			JobStatus status = r.getStatus();
			if(JobStatus.RUNNING != status) {
				continue;
			}
			JobNodeDTO jobNodeDTO = new JobNodeDTO();
			jobNodeDTO.setJobId(job.getJobId());
			jobNodeDTO.setNodeName(r.getNodeName());
			jobNodeDTO.setNodeCode(r.getNodeCode());
			jobNodeDTO.setRunType(RunType.valueOf(r.getRunType()));
			jobNodeDTO.setStatus(status);
			jobNodeDTO.setId(r.getId());
			JobDTO jobDTO = new JobDTO();
			BeanUtils.copyProperties(job, jobDTO);
			jobDTO.setJobType(JobType.valueOf(job.getJobType()));
			jobNodeDTO.setJobDTO(jobDTO);
			return jobNodeDTO;
		}
		return null;
	}

	@Override
	@Transactional
	public Boolean saveJobNodeStatus(JobNodeDTO jobNodeDTO, JobStatus status, String message) {
		Job job = jobDao.getById(jobNodeDTO.getJobId());
		JobNode jobNode = new JobNode();
		jobNode.setId(jobNodeDTO.getId());
		jobNode.setStatus(status);
		jobNode.setMessage(message);
		jobNode.setUpdateTime(LocalDateTime.now());
		JobStatus beforeStatus = null;
		if(status == JobStatus.RUNNING) {
			jobNode.setStartTime(LocalDateTime.now());
			jobNode.setExecIp(jobNodeDTO.getExecIp());
			beforeStatus = JobStatus.WAIT;
			job.setStartTime(LocalDateTime.now());
		}else if(status != JobStatus.WAIT) {
			jobNode.setEndTime(LocalDateTime.now());
			beforeStatus = JobStatus.RUNNING;
			job.setEndTime(LocalDateTime.now());
		}
		boolean hasChange = jobNodeDao.updateByIdAndStatus(jobNode, beforeStatus);
		if(!hasChange) {
			return false;
		}
		job.setStatus(status);
		job.setMessage(message);
		job.setUpdateTime(LocalDateTime.now());
		job.setLastSyncTime(LocalDateTime.now());
		if(StringUtils.hasText(jobNodeDTO.getExecIp())) {
			job.setExecIp(jobNodeDTO.getExecIp());
		}
		jobDao.updateById(job);
		return true;
	}
	
	@Override
	public Boolean saveJobStatus(JobDTO jobDTO, JobStatus status, String message) {
		Job job = jobDao.getById(jobDTO.getJobId());
		JobStatus beforeStatus = null;
		if(status == JobStatus.RUNNING) {
			job.setStartTime(LocalDateTime.now());
			beforeStatus = JobStatus.WAIT;
		}else if(status != JobStatus.WAIT) {
			job.setEndTime(LocalDateTime.now());
			beforeStatus = JobStatus.RUNNING;
		}
		job.setStatus(status);
		job.setMessage(message);
		job.setUpdateTime(LocalDateTime.now());
		job.setLastSyncTime(LocalDateTime.now());
		if(StringUtils.hasText(jobDTO.getExecIp())) {
			job.setExecIp(jobDTO.getExecIp());
		}
		boolean hasChange = jobDao.updateByIdAndStatus(job, beforeStatus);
		if(!hasChange) {
			return false;
		}
		return true;
	}

	@Override
	@Transactional
	public void stopJobByBiz(String bizType, String bizId) {
		Job job = jobDao.findJob(bizType, bizId);
		if(null == job){
			return;
		}
		jobAppService.stopJob(job);
	}

	/**
	@Override
	public JobDTO getJob(String jobGroup, String bizId) {
		// TODO Auto-generated method stub
		return null;
	}
	*/

	@Override
	public JobDTO getJob(String jobId) {
		Job job = jobDao.getById(jobId);
		JobDTO jobDTO = new JobDTO();
		BeanUtils.copyProperties(job, jobDTO);
		jobDTO.setJobType(JobType.valueOf(job.getJobType()));
		return jobDTO;
	}

	@Override
	public void saveJobHeartbeat(String jobId) {
		Job job = new Job();
		job.setJobId(jobId);
		job.setLastSyncTime(LocalDateTime.now());
		jobDao.updSyncTime(job);
	}

}
